package com.liaoyoule.multiple.service.impl;

import com.liaoyoule.multiple.dao.page.PageInfo;
import com.liaoyoule.multiple.dao.repository.UserRepository;
import com.liaoyoule.multiple.dao.spec.SpecificationHelper;
import com.liaoyoule.multiple.exception.NotFoundParameterizedException;
import com.liaoyoule.multiple.query.MultipleQuery;
import com.liaoyoule.multiple.service.IBaseService;
import com.liaoyoule.multiple.util.SpringContextUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by cdyoue on 2017/2/24.
 */
public abstract class BaseServiceImpl<T, DTO> implements IBaseService<T, DTO> {
    private static final Logger log = LoggerFactory.getLogger(BaseServiceImpl.class);
    @Autowired
    private SpecificationHelper specificationHelper;

    protected abstract Class getJpaRepositoryClazz();

    private JpaRepository getJpaRepository() {
        return (JpaRepository) SpringContextUtil.getBean(getJpaRepositoryClazz());
    }

    private JpaSpecificationExecutor<T> getJpaSpecificationExecutor() {
        return (JpaSpecificationExecutor<T>) SpringContextUtil.getBean(getJpaRepositoryClazz());
    }


    public PageInfo<DTO> listPageinfo(List<MultipleQuery> multipleQueries, Integer page, Integer pageSize, Sort sort) {
        Class daClazz = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        Specification specifica = specificationHelper.getSpecifica(daClazz, multipleQueries);
        PageRequest pageRequest = new PageRequest(page, pageSize, sort);
        Page<T> pageDAO = getJpaSpecificationExecutor().findAll(specifica, pageRequest);
        List<DTO> dtos = pageDAO.getContent().stream().map(p -> transformDaoToDto((p))).collect(Collectors.toList());
        return new PageInfo(new PageImpl<>(dtos, pageRequest, pageDAO.getTotalElements()));
    }


    @Override
    public DTO listInfo(Integer id) {
        T one = (T) getJpaRepository().findOne(id);
        return transformDaoToDto(one);
    }

    @Override
    public DTO listInfo(T entity) {
        Example<T> example = Example.of(entity);

        T one = (T) getJpaRepository().findOne(example);

        return transformDaoToDto(one);

    }

    ;


    @Override
    public DTO save(T entity) {
        T one = (T) getJpaRepository().saveAndFlush(entity);
        return transformDaoToDto(one);
    }

    ;

    @Override
    public DTO updateSelective(T entity) {
        return null;
    }

    ;

    @Override
    @Transactional
    public void batchDelete(List<String> ids) {
        List<String> errors = new ArrayList<>();
        ids.forEach(p->{
            try {
                getJpaRepository().delete(Integer.parseInt(p));
            } catch (EmptyResultDataAccessException e) {
                log.error(e.getMessage());
                errors.add((String) p);
            }
        });
        Class clazz = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        if(errors.size() != 0){
            String parm = StringUtils.join(errors, "");
            throw new NotFoundParameterizedException(new StringBuffer(clazz.getSimpleName())
                    .append("没有找到").toString(),new StringBuffer("id为:")
                    .append(StringUtils.join(errors.toArray(),"、") )
                    .toString());
        }

    }
    /**
     * 将 Dao转换为 DTO
     *
     * @param dao
     * @return
     */
    protected DTO transformDaoToDto(T dao) {
        Class dtoClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
        try {
            DTO dto = (DTO) dtoClass.newInstance();
            BeanUtils.copyProperties(dao, dto);
            return dto;
        } catch (InstantiationException e) {
            e.printStackTrace();
            log.error("对象转换 创建实例错误" + e.getMessage());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            log.error("对象转换 错误" + e.getMessage());
        }
        return null;
    }


}
